package parse

import "fmt"

const (
	NodeType_BoolNode = iota
	NodeType_CharacterNode
	NodeType_CommentNode
	NodeType_DerefNode
	NodeType_FnLiteralNode
	NodeType_IgnoreFormNode
	NodeType_KeywordNode
	NodeType_ListNode
	NodeType_MapNode
	NodeType_MetadataNode
	NodeType_NewlineNode
	NodeType_NilNode
	NodeType_NumberNode
	NodeType_QuoteNode
	NodeType_RegexNode
	NodeType_SetNode
	NodeType_StringNode
	NodeType_SymbolNode
	NodeType_SyntaxQuoteNode
	NodeType_TagNode
	NodeType_UnquoteNode
	NodeType_UnquoteSpliceNode
	NodeType_VarQuoteNode
	NodeType_VectorNode
	NodeType_FunctionNode
	NodeType_ObjectNode
	NodeType_NativeFunction
)

type Node interface {
	Position() *Pos
	String() string // A non-recursive string representation
	Children() []Node
	HashCode() interface{}
	Type() int
}

func (p *Pos) Position() *Pos { return p }

type BoolNode struct {
	*Pos
	Val bool
}

func (this BoolNode) HashCode() interface{} {
	return this.Val
}
func (this BoolNode) Type() int { return NodeType_BoolNode }
func (n BoolNode) String() string {
	if n.Val {
		return "true"
	}
	return "false"
}

func (n BoolNode) Children() []Node { return nil }

type CharacterNode struct {
	*Pos
	Val  rune
	Text string
}

func (this CharacterNode) HashCode() interface{} { return this }
func (n CharacterNode) String() string           { return fmt.Sprintf("char(%q)", n.Val) }
func (n CharacterNode) Children() []Node         { return nil }
func (this CharacterNode) Type() int             { return NodeType_CharacterNode }

type CommentNode struct {
	*Pos
	Text string
}

func (this CommentNode) HashCode() interface{} { return this }
func (n CommentNode) String() string           { return fmt.Sprintf("comment(%q)", n.Text) }
func (n CommentNode) Children() []Node         { return nil }
func (this CommentNode) Type() int             { return NodeType_CommentNode }

type DerefNode struct {
	*Pos
	Node Node
}

func (this DerefNode) HashCode() interface{} { return this }
func (n DerefNode) String() string           { return "deref" }
func (n DerefNode) Children() []Node         { return []Node{n.Node} }
func (this DerefNode) Type() int             { return NodeType_DerefNode }

type KeywordNode struct {
	*Pos
	Val string
}

func (this KeywordNode) HashCode() interface{} { return this.Val }
func (n KeywordNode) String() string           { return fmt.Sprintf("keyword(%s)", n.Val) }
func (n KeywordNode) Children() []Node         { return nil }
func (this KeywordNode) Type() int             { return NodeType_KeywordNode }

type ListNode struct {
	*Pos
	Nodes []Node
}

func (this ListNode) HashCode() interface{} { return this }
func (n ListNode) String() string {
	return fmt.Sprintf("list(length=%d)", countSemantic(n.Nodes))
}
func (n ListNode) Children() []Node { return n.Nodes }
func (this ListNode) Type() int     { return NodeType_ListNode }

type MapNode struct {
	*Pos
	Val map[interface{}]interface{}
}

func (this MapNode) HashCode() interface{} { return this }
func (n MapNode) String() string {
	return fmt.Sprintf("map(length=%d)", n.Val)
}
func (n MapNode) Children() []Node { return nil }
func (this MapNode) Type() int     { return NodeType_MapNode }

type MetadataNode struct {
	*Pos
	Node Node
}

func (this MetadataNode) HashCode() interface{} { return this }
func (n MetadataNode) String() string           { return "metadata" }
func (n MetadataNode) Children() []Node         { return []Node{n.Node} }
func (this MetadataNode) Type() int             { return NodeType_MetadataNode }

type NewlineNode struct {
	*Pos
}

func (this NewlineNode) HashCode() interface{} { return this }
func (n NewlineNode) String() string           { return "newline" }
func (n NewlineNode) Children() []Node         { return nil }
func (this NewlineNode) Type() int             { return NodeType_NewlineNode }

type NilNode struct {
	*Pos
}

func (this NilNode) HashCode() interface{} { return this }
func (n NilNode) String() string           { return "nil" }
func (n NilNode) Children() []Node         { return nil }
func (this NilNode) Type() int             { return NodeType_NilNode }

type NumberNode struct {
	*Pos
	Val interface{}
}

func (this NumberNode) HashCode() interface{} { return this.Val }
func (n NumberNode) String() string           { return fmt.Sprintf("num(%s)", n.Val) }
func (n NumberNode) Children() []Node         { return nil }
func (this NumberNode) Type() int             { return NodeType_NumberNode }

type SymbolNode struct {
	*Pos
	Val string
}

func (this SymbolNode) HashCode() interface{} { return this }
func (n SymbolNode) String() string           { return "sym(" + n.Val + ")" }
func (n SymbolNode) Children() []Node         { return nil }
func (this SymbolNode) Type() int             { return NodeType_SymbolNode }

type QuoteNode struct {
	*Pos
	Node Node
}

func (this QuoteNode) HashCode() interface{} { return this }
func (n QuoteNode) String() string           { return "quote" }
func (n QuoteNode) Children() []Node         { return []Node{n.Node} }
func (this QuoteNode) Type() int             { return NodeType_QuoteNode }

type StringNode struct {
	*Pos
	Val string
}

func (this StringNode) HashCode() interface{} { return this.Val }
func (n StringNode) String() string           { return fmt.Sprintf("string(%q)", n.Val) }
func (n StringNode) Children() []Node         { return nil }
func (this StringNode) Type() int             { return NodeType_StringNode }

type SyntaxQuoteNode struct {
	*Pos
	Node Node
}

func (this SyntaxQuoteNode) HashCode() interface{} { return this }
func (n SyntaxQuoteNode) String() string           { return "syntax quote" }
func (n SyntaxQuoteNode) Children() []Node         { return []Node{n.Node} }
func (this SyntaxQuoteNode) Type() int             { return NodeType_SyntaxQuoteNode }

type UnquoteNode struct {
	*Pos
	Node Node
}

func (this UnquoteNode) HashCode() interface{} { return this }
func (n UnquoteNode) String() string           { return "unquote" }
func (n UnquoteNode) Children() []Node         { return []Node{n.Node} }
func (this UnquoteNode) Type() int             { return NodeType_UnquoteNode }

type UnquoteSpliceNode struct {
	*Pos
	Node Node
}

func (this UnquoteSpliceNode) HashCode() interface{} { return this }
func (n UnquoteSpliceNode) String() string           { return "unquote splice" }
func (n UnquoteSpliceNode) Children() []Node         { return []Node{n.Node} }
func (this UnquoteSpliceNode) Type() int             { return NodeType_UnquoteSpliceNode }

type VectorNode struct {
	*Pos
	Nodes []Node
}

func (this VectorNode) HashCode() interface{} { return this }
func (n VectorNode) String() string {
	return fmt.Sprintf("vector(length=%d)", countSemantic(n.Nodes))
}
func (n VectorNode) Children() []Node { return n.Nodes }
func (this VectorNode) Type() int     { return NodeType_VectorNode }

type FunctionNode struct {
	*Pos
	ListNode    *ListNode
	VecArgsNode *VectorNode
}

func (this FunctionNode) HashCode() interface{} { return this }
func (n FunctionNode) String() string {
	return fmt.Sprintf("lambda(length=%d)", countSemantic(n.ListNode.Children()))
}
func (n FunctionNode) Children() []Node { return n.ListNode.Children() }
func (this FunctionNode) Type() int     { return NodeType_FunctionNode }

type IgnoreFormNode struct {
	*Pos
	Node Node
}

func (this IgnoreFormNode) HashCode() interface{} { return this }
func (n IgnoreFormNode) String() string           { return "ignore" }
func (n IgnoreFormNode) Children() []Node         { return []Node{n.Node} }
func (this IgnoreFormNode) Type() int             { return NodeType_IgnoreFormNode }

type RegexNode struct {
	*Pos
	Val string
}

func (this RegexNode) HashCode() interface{} { return this }
func (n RegexNode) String() string           { return fmt.Sprintf("regex(%q)", n.Val) }
func (n RegexNode) Children() []Node         { return nil }
func (this RegexNode) Type() int             { return NodeType_RegexNode }

type SetNode struct {
	*Pos
	Nodes []Node
}

func (this SetNode) HashCode() interface{} { return this }
func (n SetNode) String() string {
	return fmt.Sprintf("set(length=%d)", countSemantic(n.Nodes))
}
func (n SetNode) Children() []Node { return n.Nodes }
func (this SetNode) Type() int     { return NodeType_SetNode }

type VarQuoteNode struct {
	*Pos
	Val string
}

func (this VarQuoteNode) HashCode() interface{} { return this }
func (n VarQuoteNode) String() string           { return fmt.Sprintf("varquote(%s)", n.Val) }
func (n VarQuoteNode) Children() []Node         { return nil }
func (this VarQuoteNode) Type() int             { return NodeType_VarQuoteNode }

type TagNode struct {
	*Pos
	Val string
}

func (this TagNode) HashCode() interface{} { return this }
func (n TagNode) String() string           { return fmt.Sprintf("tag(%s)", n.Val) }
func (n TagNode) Children() []Node         { return nil }
func (this TagNode) Type() int             { return NodeType_TagNode }

type ObjectNode struct {
	*Pos
	Val interface{}
}

func (this ObjectNode) HashCode() interface{} { return this.Val }
func (n ObjectNode) String() string           { return fmt.Sprintf("Object(%s)", n.Val) }
func (n ObjectNode) Children() []Node         { return nil }
func (this ObjectNode) Type() int             { return NodeType_ObjectNode }

func isSemantic(n Node) bool {
	switch n.(type) {
	case *CommentNode, *NewlineNode:
		return false
	}
	return true
}

func countSemantic(nodes []Node) int {
	count := 0
	for _, node := range nodes {
		if isSemantic(node) {
			count++
		}
	}
	return count
}
